package com.wjk.kylin.mall.product.config;


import io.micrometer.core.instrument.MeterRegistry;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/*
 * @Aspect:给spring说明这个组件是切面类
 * try{
 * 		@Before
 * 		Result = method.invoke(obj,args);
 * 		@AfterReturing
 * }catch(e){
 * 		@AfterReturing
 * }finally{
 * 		@After
 * }
 *
 * 五个注解：
 * @Before:在目标方法之前运行；                         前置通知
 * @After:在目标方法结束之后运行；                       后置通知
 * @AfterReturing:在目标方法正常返回之后；				返回通知
 * @AfterThrowing:在目标方法抛出异常之后运行；			异常通知
 * @Around:环绕										环绕通知
 * */
@Slf4j
@Aspect
@Component
public class PrometheusMetricsAspect {
    @Autowired
    private MeterRegistry registry;

    // 切入所有controller包下的请求方法
    @Pointcut("execution(public * com.wjk.kylin.mall.product.controller.*.*(..))")
    public void controllerPointcut() {
    }

    @Around("controllerPointcut()")
    public Object metricsCollector(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        // 获取api url
        String api = request.getServletPath();
        long startTime = System.currentTimeMillis();
        String[] tags = new String[2];
        tags[0] = "api";
        tags[1] = api;
        // 请求次数加1
        registry.counter("mall_product_requests_api_all", tags).increment();
        Object object;
        try {
            object = joinPoint.proceed();
        } catch (Exception e) {
            // 请求失败次数加1
            registry.counter("mall_product_requests_api_error", tags).increment();
            throw e;
        } finally {
            long time = System.currentTimeMillis() - startTime;
            //记录请求响应时间
            registry.timer("mall_product_requests_api_time", tags).record(time, TimeUnit.MILLISECONDS);
        }
        return object;
    }
}

